#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "CtoCplus.h"


static int Shape__NShapes = 0;

typedef size_t(*Dtor)(void*);
typedef void(*Ctor)(void*);


/******************************************************************************/
/**                     class   Shape   declaration                          **/
/******************************************************************************/
typedef void(*DRAW)(void*);

typedef struct  _ShapeVTable
{
    Dtor   shapeDtor;
    DRAW        draw;
}ShapeVTable;

typedef struct _shape
{
    ShapeVTable* m_vtbl;
    int     m_id;
}Shape;

static  void Shape__PrintNShapes(void);
void    Shape__Ctor(void* _this);
void    Shape__CCtor(Shape* _this,Shape* _other);
size_t  Shape__Dtor(void* _this);
void    Shape__Draw(Shape* _this);
Shape*  Shape__Assigment__operator(Shape* _this);
static void Shape__PrintNShapes(void);

/******************************************************************************/
/**                     class    Circle                                      **/
/******************************************************************************/

typedef struct _Circle
{
    Shape   m_papa;
    int     m_radius;
}Circle;

typedef struct  _CircleVTable
{
    ShapeVTable shapeVtable;
    DRAW    radius;
}CircleVTable;

void    Circle__Ctor(void* _this);
size_t  Circle__Dtor(void* _this);
void    Circle__Draw(Circle* _circle);
void    Circle__Radius(Circle* _circle);

/******************************************************************************/
/**                     class    Square                                      **/
/******************************************************************************/

typedef struct _Square
{
    Shape   m_papa;
}Square;

void    Square__Ctor(void* _this);
size_t  Square__Dtor(void* _this);
void    Square__Draw(Square* _square);
void    Square__Draw(Square* _square);

/******************************************************************************/
/**                     Global functions                                     **/
/******************************************************************************/

void f1(Shape*  _s);
void f2(void);
void f3(Circle _c);

/******************************************************************************/
/**                    new  and detele                                       **/
/******************************************************************************/
void*   New(Ctor _ctor,size_t _size);
void*   New_bracket(Ctor _ctor,size_t _objSize,size_t _objNum);
void    Delete(Dtor _dtar,void* _obj);
void    Delete_bracket(Dtor _dtar,void* _mem);

/******************************************************************************/
/**                    Objects vtables                                       **/
/******************************************************************************/

ShapeVTable  shapeVtable  = {(size_t(*)(void*))Shape__Dtor,(void(*)(void*))Shape__Draw};
ShapeVTable  squareVTable = {(size_t(*)(void*))Square__Dtor,(void(*)(void*))Square__Draw};
CircleVTable  circleVTable= { {(size_t(*)(void*))Circle__Dtor,(void(*)(void*))Circle__Draw}, (void(*)(void*))Circle__Radius };

/******************************************************************************/
/**                    new  and detele  Imp                                  **/
/******************************************************************************/

void*   New(Ctor _ctor,size_t _size)
{
    void* temp = malloc(_size);

    if(!temp)
    {
        fprintf(stderr,"cannot alloc memmory ");

        return 0;
    }

    _ctor(temp);

    return temp;
}

void*   New_bracket(Ctor _ctor,size_t _objSize,size_t _objNum)
{
    int i = 0;
    void* temp = malloc((_objSize*_objNum)+sizeof(int));

    if(!temp)
    {
        fprintf(stderr,"cannot alloc memmory ");

        return 0;
    }

    *(int*)temp = _objSize*_objNum;

    for(i = 0 ; i < (int)(_objSize*_objNum) ;i += _objSize )
    {
        _ctor((char*)temp + sizeof(int)+i);
    }

    return ((char*)temp + sizeof(int));
}


void    Delete(Dtor _dtor,void* _obj)
{
    _dtor(_obj);
    free(_obj);
}

void    Delete_bracket(Dtor _dtor,void* _mem)
{
    size_t  size = *(int*)( (char*)_mem - sizeof(int) );
    size_t  pos  = 0;

    while (size != pos)
    {
        pos += _dtor( (char*)_mem + sizeof(int) + pos);
    }
}

/******************************************************************************/
/**                    Shape Imp                                             **/
/******************************************************************************/


size_t   Shape__Dtor(void* _this)
{
    --Shape__NShapes;
    printf("Shape::Dtor() \n");

    return sizeof(Shape);
}

void    Shape__Draw(Shape* _this)
{
    printf("Shape::Draw() : %d \n",_this->m_id);
}

void    Shape__Ctor(void* _this)
{
    ((Shape*)_this)->m_vtbl = &shapeVtable;
    ((Shape*)_this)->m_id = (++Shape__NShapes);
    printf("Shape::Ctor() \n");
}

void    Shape__CCtor(Shape* _this,Shape* _other)
{
    _this->m_vtbl = &shapeVtable;
    _this->m_id = (++Shape__NShapes);
    printf("Shape::CCtor() \n");
}
static void Shape__PrintNShapes(void)
{
    printf("NShapes: %d \n",Shape__NShapes);
}

/******************************************************************************/
/**                    Circle Imp                                             **/
/******************************************************************************/


size_t   Circle__Dtor(void* _this)
{
    printf("Circle::Dtor() \n");
    Shape__Dtor(_this);

    return sizeof(Circle);
}

void    Circle__Draw(Circle* _this)
{
 printf("Circle::Draw() \n");
}

void    Circle__Ctor(void* _this)
{
    Shape__Ctor(_this);
    ((Circle*)_this)->m_radius = 2;
    ((Circle*)_this)->m_papa.m_vtbl = (ShapeVTable*)&circleVTable;

    printf("Circle::Ctor() \n");
}

void    Circle__CCtor(Circle* _this,Circle* _other)
{
    Shape__CCtor((Shape*)_this,(Shape*)_other);
    ((Circle*)_this)->m_papa.m_vtbl = (ShapeVTable*)&circleVTable;
    ((Circle*)_this)->m_radius = ((Circle*)_other)->m_radius;

    printf("Circle::CCtor() \n");
}

void    Circle__Radius(Circle* _circle)
{
    printf("Circle::Radius() \n");
}


/******************************************************************************/
/**                    Square Imp                                             **/
/******************************************************************************/


size_t   Square__Dtor(void* _this)
{
    printf("Square::Dtor() \n");
    Shape__Dtor(_this);

    return sizeof(Square);
}

void    Square__Draw(Square* _this)
{
 printf("Square::Draw() \n");
}

void    Square__Ctor(void* _this)
{
    Shape__Ctor(_this);

    ((Square*)_this)->m_papa.m_vtbl = (ShapeVTable*)&squareVTable;

    printf("Square::Ctor() \n");
}

void    Square__CCtor(Square* _this,Square* _other)
{
    Shape__CCtor((Shape*)_this,(Shape*)_other);
    ((Square*)_this)->m_papa.m_vtbl = (ShapeVTable*)&squareVTable;
    printf("Square::CCtor() \n");
}

void f3(Circle c)
{
    Circle temp;
    Circle__CCtor(&temp,&c);
    temp.m_papa.m_vtbl->draw(&c);
    Circle__Dtor(&temp);
}

int main()
{
    Circle c;
    Circle c2;
    int i = 0;
    /*f3(c);*/

    Shape *array[3];
    Shape arr2[3];
    Shape arrT2[3];
    Square *arr4 ;
    Circle arr3[4];

    Circle__Ctor(&c); /*Circle c;*/
    f3(c);


/*    Shape *array[] =
	{
	    new Circle(),
	    new Square(),
	    new Circle()
	};*/
    array[0] = (Shape*)New(Circle__Ctor,sizeof(Circle));
	array[1] = (Shape*)New(Square__Ctor,sizeof(Square));
	array[2] = (Shape*)New(Circle__Ctor,sizeof(Circle));

/*for(int i = 0; i < 3; ++i) array[i]->Draw();*/
    for(i = 0; i < 3; ++i) array[i]->m_vtbl->draw(array[i]);

/*for(int i = 0; i < 3; ++i) delete array[i];*/
    for(i = 0;i < 3;i++)
    {
        Delete(array[i]->m_vtbl->shapeDtor,array[i]);
    }

/*    Shape arr2[] =
	{
	    Circle(),
	    Square(),
	    Shape()
	}; */

    Circle__Ctor(&arrT2[0]);
    Shape__CCtor((Shape*)&arr2[0],(Shape*)&arrT2[0]);
    Circle__Dtor(&arrT2[0]);

    Square__Ctor(&arrT2[1]);
    Shape__CCtor((Shape*)&arr2[1],(Shape*)&arrT2[1]);
    Square__Dtor(&arrT2[1]);

    Shape__Ctor(&arr2[2]);
/*    Shape__CCtor(&arr2[2],&arrT2[2]);
    Shape__Dtor(&arrT2[2]);*/

/*for(int i = 0; i < 3; ++i) arr2[i].Draw();*/
    for( i = 0; i < 3; ++i) arr2[i].m_vtbl->draw(&arr2[i]);

/*Shape::PrintNShapes();*/
    Shape__PrintNShapes();

/*    Circle c2;
    c2.PrintNShapes();*/
    Circle__Ctor(&c2);
    Shape__PrintNShapes();

/*Circle arr3[4];*/
    for(i = 0;i<4 ;++i)
    {
       Circle__Ctor(&arr3[i]);
    }

/*Square *arr4 = new Square[4];*/
    arr4 = (Square*)New_bracket(Square__Ctor,sizeof(Square),4);

/* delete [] arr4;*/
    Delete_bracket(Square__Dtor,arr4);

            /*Dtors*/
    for(i = 3;i>0 ;--i)
    {
       Circle__Dtor(&arr3[i]);
    }
    Circle__Dtor(&c2);
    Shape__Dtor(&arr2[2]);
    Shape__Dtor(&arr2[1]);
    Shape__Dtor(&arr2[0]);
    Circle__Dtor(&c);
    return 0;
}
